package ar.com.laley.centro.session;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public abstract class SessionManager implements Filter{
    protected static ThreadLocal hibernateHolder = new ThreadLocal(); 
    protected static ThreadLocal txHolder = new ThreadLocal(); 
    protected static SessionFactory factory;
    
     public void init(FilterConfig filterConfig) throws ServletException
     {
        // Initialize hibernate
        try
        {
            factory = new Configuration().configure().buildSessionFactory();
        }
        catch (HibernateException ex) { throw new ServletException(ex); }
     }
     
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
                   throws IOException, ServletException
    {
        if (hibernateHolder.get() != null)
            throw new IllegalStateException(
                "A session is already associated with this thread!  "
                + "Someone must have called getSession() outside of the context "
                + "of a servlet request.");
            
        try
        {
            chain.doFilter(request, response);
        }
        finally
        {
            Session sess = (Session)hibernateHolder.get();
            Transaction tx = (Transaction)txHolder.get();
            if (sess != null)
            {
                hibernateHolder.set(null);
                
                try
                {
                    if (tx != null) {
                        tx.commit();
                    }
                    sess.close();
                }
                catch (HibernateException ex) { throw new ServletException(ex); }
            }
        }
    }
    
    public static Session getSession() throws HibernateException
    {
        Session sess = (Session)hibernateHolder.get();
        Transaction tx = (Transaction)txHolder.get();
                
        if (sess == null)
        {
            sess = factory.openSession();
            txHolder.set(sess.beginTransaction());
            hibernateHolder.set(sess);
        } else {
            if (tx == null) {
                throw new IllegalStateException("Transaction was allready rolled back");
            }
        }    
        return sess;
    }
    
    public static void rollback() throws HibernateException {
        Transaction tx = (Transaction)txHolder.get();
        if (tx == null) {
            throw new IllegalStateException("Transaction was allready rolled back");
        }
        
        tx.rollback();
        txHolder.set(null);
    }
            
    
    public void destroy() {
        try {
            factory.close();
        }
        catch (HibernateException ex) { throw new RuntimeException(ex); }
    }       
}

